'use strict'
const http=require('http');
const fs=require('fs');
const fsp=fs.promises
// const { SSL_OP_COOKIE_EXCHANGE } = require('constants');
// const { resolve } = require('path/posix');
//解析文件扩展名
function parseExtName(filename){
    if(filename.length<2){
        return ''
    }

    let nsplit=filename.split('.').filter(p=>p.length>0)

    if(nsplit.length<2) return ''

    return `.${nsplit[nsplit.length-1]}`
}
/**------------  解析Body数据--------------- */
/**
 * Content-Disposition:form-data;name="file";filename="xxx"
 * @param {string} headerData 
 */
function parseBodyHeader(headerData){
    let hlist=headerData.split('\r\n').filter(p=>p.length>0)
    //解析content-disposition=>hlist[0]
    //按照; 切分数组，选出从第二个元素开始的数组
    let csplit=hlist[0].split('; ').slice(1);
    let filename
    let name
    for(let a of csplit){
        if(a.indexOf('filename='===0)){
             filename=a.substring(a.indexOf('=')+2,a.length-1);
        }else{
         name=a.substring(a.indexOf('=')+2,a.length-1);
        }
    }
    let headers={}
    let ind=0
let k
for(let h of hlist){
    ind=h.indexOf(':')
    k=h.substring(0,ind).toLowerCase()
    headers[k]=h.substring(ind+1).trim()
}
return{
    filename,
    name,
    headers,
    contentType:headers['content-type']||''
}
};
function parseBody(bodyData,headers){
    let ctype=headers['content-type'];
    let bdy=ctype.substring(ctype.indexOf('=')+1);
    let crlf_bdy=`\r\n--${bdy}`;
    let header_end_index=bodyData.indexOf('\r\n\r\n',crlf_bdy.length);
    let headerData=bodyData.toString('utf8',crlf_bdy.length,header_end_index);
    //解析文件头信息
    let hd=parseBodyHeader(headerData);
    let file={
        start:header_end_index+4,
        end:bodyData.indexOf(crlf_bdy,header_end_index),
        ...hd
    }
    file.length=file.end-file.start

    return file;

}
/*    解析Body数据结束*/ 

//get请求
let html=`
<!DOCTYPE html>
<html>
  <head>
   <title>First HTTP</title>
  </head>
  <body>
   你好
   </body>
</html>
`
let routerTable={
    GET:{
    '/':async(ctx)=>{
        ctx.response.setHeader('content-type','text/html;charset=utf-8')
        ctx.end(html);
    },
    '/test':async(ctx)=>{
        let status=parseInt(Math.random()*200)+199
        response.statusCode=status
        ctx.end('test end')
    },
    '/upload':async(ctx)=>{
       let stm=fs.createReadStream('./upload.html')
       stm.pipe(ctx.response,{end:false});
       stm.on('end',()=>{
        ctx.end();
       })
    }  
}, 
POST:{
    '/data':async(ctx)=>{
        let file=parseBody(ctx.rawBody,ctx.headers)
        console.log(file)
        if(!ctx.rawBody){
            ctx.end()
            return;
        }
        let fname=`${Date.now()}-${Math.random()}`+`${parseExtName(file.filename)}`
        let fn=await fsp.open(fname,'w+')
        let fret=await fn.write(ctx.rawBody,file.start,file.length,0);
        fn.close();
        ctx.end(`${fret.bytesWritten}`)
    }}
}

http.createServer(async(request,response)=>{
    //content-type不影响内容处理方式
//    response.setHeader('content-type','text/html;charset=utf-8')
    let rm=routerTable[request.method];
    let usplit=request.url.split('?')
    let pathname=usplit[0];
    let querystring=usplit[1]||'';
    if(!rm||!rm[pathname]){
      response.statusCode=404
      response.end('page not found')
      return
    }
//ctx 是content的缩写，意为请求上下文，就是一个打包了各种数据和方法的对象
let ctx={
    method:request.method,
    path:pathname,
    search:querystring,
    headers:request.headers,
    response:response,
    end:(data,encoding='utf8')=>{
        response.end(data,encoding)
    },
    write:(data,encoding='utf8')=>{
        response.write(data,encoding)
    },
    totalLength:0,
    rawBody:null,
    bufferList:[]
}
await new Promise((rv,rj)=>{
    if('PD'.indexOf(request.method[0])>=0){
      request.on('data',chunk=>{
          ctx.bufferList.push(chunk)
          ctx.totalLength+=chunk.length
      })
    }else{
    request.on('data',data=>{
      response.stateusCode=400
      response.end('bad rquest',()=>{
        request.destroy()
      })
    })
   }
    let resolve=false;
    request.on('end',()=>{
        resolve=true;
       rv();

    })
    request.on('close',()=>{
     (!resolve)&&rv()
    })
})
if(!response.writable ||response.writableEnded){
    return
}
if(ctx.bufferList.length>0){
    ctx.rawBody=Buffer.concat(ctx.bufferList,ctx.totalLength)
    ctx.bufferList=[]
}
 rm[pathname](ctx)

}).listen(3456)
//    response.setHeader('content-type','text/plain;charset=utf-8')
    // response.end(html)